from rest_framework import serializers
from django.db import transaction

from goods.models import SKU, GoodsCategory, SpecificationOption, SPUSpecification, SKUSpecification
from celery_tasks.detail.tasks import generate_static_sku_detail_html


class SKUSpecificationSerializer(serializers.ModelSerializer):
    """
            sku具体规格表数据
    """
    spec_id = serializers.IntegerField()
    option_id = serializers.IntegerField()

    class Meta:
        model = SKUSpecification
        fields = ('spec_id', 'option_id')


class SKUSerializer(serializers.ModelSerializer):
    """
    sku 序列化器
    """

    spu_id = serializers.IntegerField()
    category_id = serializers.IntegerField()

    # 通过SKUSpecification sku字段 related_name='specs' // specification_set
    specs = SKUSpecificationSerializer(read_only=True, many=True)

    class Meta:
        model = SKU
        fields = '__all__'
        read_only_fields = ('spu', 'category')

    def create(self, validated_data):
        specs = self.context['request'].data.get('specs')
        # 开启事务
        with transaction.atomic():
            # 设置保存点
            save_point = transaction.savepoint()
            try:
                # 保存sku表
                sku = SKU.objects.create(**validated_data)
                # 保存sku具体规格表
                for spec in specs:
                    SKUSpecification.objects.create(spec_id=spec['spec_id'], option_id=spec['option_id'], sku=sku)

            except:
                # 回滚
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError('保存失败')

            else:

                # 生成详情页的静态页面
                generate_static_sku_detail_html.delay(sku.id)

                # 提交
                transaction.savepoint_commit(save_point)

                return sku

    def update(self, instance, validated_data):
        specs = self.context['request'].data.get('specs')
        # 开启事务
        with transaction.atomic():
            # 设置保存点
            save_point = transaction.savepoint()
            try:
                # 修改sku表  通过这种方法我们可以使用到序列化器update(**validated_data)
                SKU.objects.filter(id=instance.id).update(**validated_data)
                # 修改sku具体规格表
                """
                考虑到弊端：修改规格存在规格参数不一致。
                    采用先删除后添加的形式。可以避免这一问题
                """
                SKUSpecification.objects.filter(sku_id=instance.id).delete()
                for spec in specs:
                    SKUSpecification.objects.create(spec_id=spec['spec_id'], option_id=spec['option_id'], sku=instance)
            except:
                # 回滚
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError('修改失败')

            else:

                # 生成详情页的静态页面
                generate_static_sku_detail_html.delay(instance.id)

                # 提交
                transaction.savepoint_commit(save_point)
                return instance


class GoodsCategorySerializer(serializers.ModelSerializer):
    """
    商品分类 序列化器
    """

    class Meta:
        model = GoodsCategory
        fields = '__all__'


class SpecificationOptionSerializer(serializers.ModelSerializer):
    """
        规格选项序列化器
    """

    class Meta:
        model = SpecificationOption
        fields = ('id', 'value')


class SPUSpecSerializer(serializers.ModelSerializer):
    """
        规格序列化器
    """
    # 关联序列化返回SPU表数据
    # spu = serializers.StringRelatedField(read_only=True)
    # spu_id = serializers.IntegerField(read_only=True)
    # 关联序列化返回 规格选项信息
    options = SpecificationOptionSerializer(read_only=True, many=True)  # 使用规格选项序列化器

    class Meta:
        model = SPUSpecification  # SPUSpecification中的外键spu关联了SPU商品表
        fields = "__all__"
